package com.cl.base.auth.service.impl;

import cn.hutool.json.JSONUtil;
import com.cl.base.auth.dto.PayloadDto;
import com.cl.base.auth.entity.AuthUser;
import com.cl.base.auth.service.JwtTokenService;
import com.cl.base.constant.ResultCode;
import com.cl.base.constant.SecurityConstants;
import com.cl.base.exception.ServiceException;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jose.crypto.MACVerifier;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.text.ParseException;
import java.time.Duration;
import java.time.Instant;
import java.util.Collections;
import java.util.UUID;

/**
 * JWT处理的业务类
 */
@Service
public class JwtTokenServiceImpl implements JwtTokenService {
    @Override
    public String getToken(HttpServletRequest request) {
        String authHeader = request.getHeader(SecurityConstants.TOKEN_HEADER);
        if (authHeader != null && authHeader.startsWith(SecurityConstants.TOKEN_HEAD)) {
            return authHeader.substring(SecurityConstants.TOKEN_HEAD.length());
        }
        return null;
    }

    @Override
    public String generateTokenByHMAC(String payloadStr, String secret) {
        //创建JWS头，设置签名算法和类型
        JWSHeader jwsHeader = new JWSHeader.Builder(JWSAlgorithm.HS256).type(JOSEObjectType.JWT).build();
        //将负载信息封装到Payload中
        Payload payload = new Payload(payloadStr);
        //创建JWS对象
        JWSObject jwsObject = new JWSObject(jwsHeader, payload);
        //创建HMAC签名器
        JWSSigner jwsSigner;
        try {
            jwsSigner = new MACSigner(secret);
            jwsObject.sign(jwsSigner);
        } catch (JOSEException e) {
            throw new ServiceException(ResultCode.GENERATE_TOKEN_ERROR);
        }
        //签名
        return jwsObject.serialize();
    }

    @Override
    public String generateTokenByHMAC(String payloadStr) {
        return generateTokenByHMAC(payloadStr, SecurityConstants.SECRET);
    }

    @Override
    public PayloadDto getPayloadDtoByHMAC(String token, String secret) {
        if (token == null) {
            return null;
        }
        //从token中解析JWS对象
        JWSObject jwsObject;
        try {
            jwsObject = JWSObject.parse(token);
            JWSVerifier jwsVerifier = new MACVerifier(secret);
            //创建HMAC验证器
            if (!jwsObject.verify(jwsVerifier)) {
                return null;
            }
        } catch (ParseException | JOSEException e) {
            return null;
        }
        String payload = jwsObject.getPayload().toString();
        return JSONUtil.toBean(payload, PayloadDto.class);
    }

    @Override
    public PayloadDto getPayloadDtoByHMAC(String token) {
        return getPayloadDtoByHMAC(token, SecurityConstants.SECRET);
    }

    @Override
    public PayloadDto createPayloadDto(AuthUser authUser) {
        Instant now = Instant.now();
        long iat = now.getEpochSecond();
        long exp = now.plus(Duration.ofDays(3)).getEpochSecond();
        return PayloadDto.builder()
                .sub("cl-base")
                .iat(iat)
                .exp(exp)
                .jti(UUID.randomUUID().toString())
                .username(authUser.getUsername())
//                .authorities(authUser.getAuthorities())
                .build();
    }


    @Override
    public boolean validateToken(PayloadDto payloadDto, UserDetails userDetails) {
        if (payloadDto.getExp() < Instant.now().getEpochSecond()) {
            return false;
        }
        if (userDetails == null) {
            return false;
        }
        return payloadDto.getUsername().equals(userDetails.getUsername());
    }

}
